package com.hmall.cart;

/**
 * Hello world!
 *
 */

import com.hmall.api.client.ItemClient;
import com.hmall.api.config.DefaultFeignConfig;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@MapperScan("com.hmall.cart.mapper")
/*@SpringBootApplication 是 Spring Boot 的核心注解，标注在主类上，具备以下功能：
自动配置 Spring 和第三方库的 Bean；
扫描当前包及其子包中的组件（如 @Component、@Service 等）；
启用 Spring Boot 的自动配置机制。*/
//跳转到源码有@Configuration，可以自定义bean
@SpringBootApplication
/*@EnableDiscoveryClient 是Spring Cloud中的注解，
用于将当前服务注册到服务发现组件（如Eureka、Consul等），使其能被其他服务发现和调用。*/
@EnableDiscoveryClient
//@EnableFeignClients 是 Spring Cloud Feign 的注解，用于启用 Feign 客户端的功能。
// 它允许在 Spring Boot 应用中通过 Feign 客户端与多个服务进行通信,openfeign的调用者要加这个
//用basepackage也行。
/*@SpringBootApplication这个注解中包含了@ComponentScan, 这个注解会扫描当前包(com.hmall.cart)中的文件,
而ItemClient由于被抽离到hm-api模块包下(com.hmall.api), 两者包的位置不同, 所以springboot扫描不到.那么解决方法有:
1. 扩大扫描包的范围, 那么在启动类上添加"@ComponentScan({"com.hmall.cart","com.hmall.api"})",但此方法不推荐.
2. 使用"@import"注解, "@EnableFeignClients"就包含了@import注解, 由第三方依赖提供的 @EnableXxxxx注解,
basePackages选项可以简化我们的操作, 不需要自己使用@Import.*/
//第二个参数不要用@Configuration，因为这个注解在api模块，每次调用的地方都在其他模块
@EnableFeignClients(clients = {ItemClient.class},defaultConfiguration = DefaultFeignConfig.class)

public class CartApplication
{
    public static void main( String[] args )
    {
        SpringApplication.run(CartApplication.class, args);
    }

/*  该代码定义了一个 RestTemplate Bean，用于在 Spring 应用中发起 HTTP 请求。
    @Bean 注解表示该方法返回的对象将被 Spring 容器管理。 方法内部创建并返回了一个新的 RestTemplate 实例。*/
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}


/*
一Java动态代理是一种在运行时动态生成代理类的技术，允许开发者在不修改原始类代码的情况下，拦截并增强目标方法的行为。
它基于反射机制实现，广泛应用于AOP（面向切面编程）、日志记录、事务管理、远程方法调用（RMI）等场景。
二、动态代理的实现方式
Java动态代理主要有两种实现方式：
JDK动态代理（基于接口）
核心组件：Proxy类与InvocationHandler接口。
要求：目标类必须实现至少一个接口。
实现步骤：
定义接口及其实现类；
创建InvocationHandler实现类，在invoke()方法中添加代理逻辑；
通过Proxy.newProxyInstance()动态生成代理对象。
示例：
public class LoggingHandler implements InvocationHandler {
    private Object target;
    public Object invoke(Object proxy, Method method, Object[] args) {
        System.out.println("方法调用前：记录日志");
        Object result = method.invoke(target, args);
        System.out.println("方法调用后：记录日志");
        return result;
    }
}
// 生成代理对象
Service proxy = (Service) Proxy.newProxyInstance(
    target.getClass().getClassLoader(),
    target.getClass().getInterfaces(),
    new LoggingHandler(target)
);
CGLIB动态代理（基于继承）
核心组件：Enhancer类与MethodInterceptor接口。
要求：目标类不能是final类，方法不能是final。
实现步骤：
添加CGLIB依赖；
创建MethodInterceptor实现类，重写intercept()方法；
通过Enhancer.create()生成代理对象。
优势：支持代理未实现接口的类。*/
